package com.cryptoneedle.garden.service.garden.source.metadata;


import com.bubbles.engine.data.core.repository.BaseRepository;
import com.bubbles.engine.data.core.service.BaseService;
import com.cryptoneedle.garden.entity.source.metadata.SourceCatalog;
import com.cryptoneedle.garden.entity.source.metadata.SourceDatabase;
import com.cryptoneedle.garden.key.DatabaseKey;
import com.cryptoneedle.garden.repository.source.metadata.SourceDatabaseRepository;
import com.cryptoneedle.garden.service.crud.garden.source.*;
import com.cryptoneedle.garden.service.util.JdbcUtil;
import com.google.common.collect.Maps;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>description: 源数据源-数据库 </p>
 *
 * @author CryptoNeedle
 * @date 2025-06-20
 */
@Slf4j
@Service
public class DatabaseService extends BaseService<SourceDatabase, DatabaseKey> {

    @Resource
    private DatabaseService databaseService;
    @Resource
    private SourceDatabaseRepository sourceDatabaseRepository;

    @Override
    public BaseRepository<SourceDatabase, DatabaseKey> getRepository() {
        return this.sourceDatabaseRepository;
    }

    @Autowired
    private FoundSourceService select;
    @Autowired
    private AddSourceService add;
    @Autowired
    private PatchSourceService patch;
    @Autowired
    private SaveSourceService save;
    @Autowired
    private DeleteSourceService delete;

    @Transactional
    public void syncDatabase(SourceCatalog catalog) {
        databaseService.syncDatabase(catalog, null);
    }

    @Transactional
    public void syncDatabase(SourceCatalog catalog, SourceDatabase database) {
        JdbcTemplate jdbcTemplate = JdbcUtil.getJdbcTemplate(catalog);
        String defaultSystemCode = database != null && StringUtils.isNotEmpty(database.getDefaultSystemCode()) ? database.getDefaultSystemCode() : catalog.getDefaultSystemCode();

        List<SourceDatabase> databases = jdbcTemplate.query(
                catalog.getDatabaseType().getDatabase().getDatabaseStatisticSql(),
                (resultSet, rowNum) ->
                        new SourceDatabase()
                                .setCatalogName(catalog.getCatalogName())
                                .setDatabaseName(resultSet.getString("database"))
                                .setTableCount(resultSet.getLong("tableCount"))
                                .setViewCount(resultSet.getLong("viewCount"))
                                .setColumnCount(resultSet.getLong("columnCount"))
                                .setConstraintCount(resultSet.getLong("constraintCount"))
                                .setIndexCount(resultSet.getLong("indexCount"))
                                .setStatisticDt(new Date())
                                .setDorisCatalogName(catalog.getDorisCatalogName())
                                .setDefaultSystemCode(defaultSystemCode)
                                .setDefaultCollectFrequency(catalog.getDefaultCollectFrequency())
                                .setEnabled(false));

        databaseService.compareData(catalog, database, databases);
    }

    @Transactional
    public void compareData(SourceCatalog catalog, SourceDatabase database, List<SourceDatabase> dealList) {
        List<SourceDatabase> originList = select.databases(catalog);
        // 已存在
        Map<String, SourceDatabase> originMap = Maps.uniqueIndex(originList, SourceDatabase::getDatabaseName);
        // 待处理
        Map<String, SourceDatabase> dealMap = Maps.uniqueIndex(dealList, SourceDatabase::getDatabaseName);

        // 新增
        List<SourceDatabase> extraList = dealList.stream().filter(deal -> !originMap.containsKey(deal.getDatabaseName())).peek(deal -> {
        }).toList();

        // 保存
        List<SourceDatabase> existsList = originList.stream()
                .filter(origin -> dealMap.containsKey(origin.getDatabaseName()))
                .peek(origin -> {
                    SourceDatabase deal = dealMap.get(origin.getDatabaseName());
                    origin.setTableCount(deal.getTableCount());
                    origin.setViewCount(deal.getViewCount());
                    origin.setColumnCount(deal.getColumnCount());
                    origin.setConstraintCount(deal.getConstraintCount());
                    origin.setIndexCount(deal.getIndexCount());
                    origin.setStatisticDt(deal.getStatisticDt());
                }).toList();

        // 移除
        List<SourceDatabase> missList = originList.stream()
                .filter(item -> !dealMap.containsKey(item.getDatabaseName()))
                .toList();

        add.databases(extraList);
        save.databases(existsList);
        delete.databases(missList);

        if (database == null) {
            log.info("[SYNC] {} -> 元数据采集 -> AbstractDatabase => 共计{} | 新增{} | 删除{}", catalog.getCatalogName(), String.format("%5d", dealList.size()), String.format("%5d", extraList.size()), String.format("%5d", missList.size()) + (
                    !missList.isEmpty() ? " => " + missList.stream().map(SourceDatabase::getDatabaseName).collect(Collectors.joining(",")) :
                            ""));
        } else {
            log.info("[SYNC] {} -> {} -> 元数据采集 -> AbstractDatabase           => 共计{} | 新增{} | 删除{}", catalog.getCatalogName(), database.getDatabaseName(), String.format("%5d", dealList.size()), String.format("%5d", extraList.size()), String.format("%5d", missList.size()) + (
                    !missList.isEmpty() ? " => " + missList.stream().map(SourceDatabase::getDatabaseName).collect(Collectors.joining(",")) :
                            ""));
        }
    }
}